﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AudiPyme.BLL
{
    //Clases que se usa en el algoritmo de cálculo de riesgos y contiene los datos principales de un activo, y las amenazas que pueden
    //generarle riesgo, ordenadas de mayor a menor nivel de riesgo según la cobertura que provean los controles asociados a la amenaza
    public class RiesgoActivo : IComparable
    {
        private int idActivo;
        private int idTipoActivo;
        private int costeActivo;//Valor del activo (en €) en caso de que se diera una amenaza que afectara al activo
        private int valorActivo;//Valor que tiene el activo para la empresa Valores(1,2,3)
        private int maximoRiesgoActivo;
        private List<NivelAmenaza> coberturaControlesAmenazaActivo;
        private List<ProbabilidadVulnerabilidad> coberturaControlesAmenazaVulnActivo;
        private List<NivelRiesgo> nivelRiesgoAmenaza;

        public RiesgoActivo()
        {
            idActivo = 0;
            idTipoActivo = 0;
            costeActivo = 0;
            valorActivo = 0;
            coberturaControlesAmenazaActivo = new List<NivelAmenaza>();
            coberturaControlesAmenazaVulnActivo = new List<ProbabilidadVulnerabilidad>();
            nivelRiesgoAmenaza = new List<NivelRiesgo>();
            maximoRiesgoActivo = -1; // Valor Centinela, el 0 se considera un nivel de riesgo dentro de nuestra escala
        }

        public RiesgoActivo(int idActivo, int idTipoActivo, int costeActivo, int valorActivo, List<NivelAmenaza> coberturaControlesAmenazaActivo,
                            List<ProbabilidadVulnerabilidad> coberturaControlesAmenazaVulnActivo, List<NivelRiesgo> nivelRiesgoAmenaza, int maximoRiesgoActivo)
        {
            this.idActivo = idActivo;
            this.idTipoActivo = idTipoActivo;
            this.costeActivo = costeActivo;
            this.valorActivo = valorActivo;
            this.coberturaControlesAmenazaActivo = coberturaControlesAmenazaActivo;
            this.coberturaControlesAmenazaVulnActivo = coberturaControlesAmenazaVulnActivo;
            this.nivelRiesgoAmenaza = nivelRiesgoAmenaza;
            this.maximoRiesgoActivo = maximoRiesgoActivo;
        }

        public int IdActivo
        {
            get { return idActivo; }
            set { idActivo = value; }
        }

        public int IdTipoActivo
        {
            get { return idTipoActivo; }
            set { idTipoActivo = value; }
        }

        public int CosteActivo
        {
            get { return costeActivo; }
            set { costeActivo = value; }
        }

        public int ValorActivo
        {
            get { return valorActivo; }
            set { valorActivo = value; }
        }

        public List<NivelAmenaza> CoberturaControlesAmenazaActivo
        {
            get { return coberturaControlesAmenazaActivo; }
            set { coberturaControlesAmenazaActivo = value; }
        }

        public List<ProbabilidadVulnerabilidad> CoberturaControlesAmenazaVulnActivo
        {
            get { return coberturaControlesAmenazaVulnActivo; }
            set { coberturaControlesAmenazaVulnActivo = value; }
        }

        public List<NivelRiesgo> NivelRiesgoAmenaza
        {
            get { return nivelRiesgoAmenaza; }
            set { nivelRiesgoAmenaza = value; }
        }

        public int MaximoRiesgoActivo
        {
            get { return maximoRiesgoActivo; }
            set { maximoRiesgoActivo = value; }
        }

        public int CompareTo(object obj)
        {
            RiesgoActivo otroRiesgoActivo = obj as RiesgoActivo;
            if (otroRiesgoActivo == null)
            {
                return 0;
            }
            switch (MaximoRiesgoActivo.CompareTo(otroRiesgoActivo.MaximoRiesgoActivo))
            {
                case 1:
                    return -1;
                case -1:
                    return 1;
                default:
                    if (CosteActivo >= otroRiesgoActivo.CosteActivo)
                    {
                        return -1;
                    }
                    else
                    {
                        return 1;
                    }
            }
        }

        //Método que calcula la cobertura de los controles asociados a una amenaza
        public int CalculaCoberturaContrAmenaza(List<ControlesCheckList> ControlesAmenaza)
        {
            //Inicializo el Nivel de Riesgo con un valor centinela
            int nivelRiesgo = -1;
            double resultadoControles = 0.0;
            //Creo las variables para poder contar el número de valores distintos de los controles
            int nControlesSI = 0, nControlesNO = 0, nControlesPARC = 0, nControlesNA = 0;
            //Recorro la lista de controles y actualizo las variables con los valores de cada uno
            for (int i = 0; i < ControlesAmenaza.Count(); i++)
            {
                switch (ControlesAmenaza[i].ValorControl)
                {
                    case "SI":
                        nControlesSI++;
                        break;
                    case "NO":
                        nControlesNO++;
                        break;
                    case "PARC":
                        nControlesPARC++;
                        break;
                    case "N/A":
                        nControlesNA++;
                        break;
                }
            }
            /*Calculo el Nivel de Riesgo que produce esa Amenaza según esta fórmula
             * 
             *                            NºControles SI + (NºControles PARCIALMENTE * 0.5)
             * ResualtadoControles = ------------------------------------------------------------------
             *                        (NºControles Totales de la Amenaza) - (NºControles NO APLICA)
             *                   
             * Dicho resultado lo normalizamos siguiendo esta metodología:
             *          0 <= ResultadoControles < 0.25    =>   Nivel Riesgo = 2 (Alto)
             *       0.25 <= ResultadoControles < 0.75    =>   Nivel Riesgo = 1 (Medio)
             *       0.75 <= ResultadoControles < 1       =>   Nivel Riesgo = 0 (Bajo)
             */
            resultadoControles = (nControlesSI + (nControlesPARC * 0.5)) / (ControlesAmenaza.Count() - nControlesNA);
            if (resultadoControles < 0.25)
            {
                //RiesgoAlto
                nivelRiesgo = 2;
            }
            else if (resultadoControles < 0.75)
            {
                //RiesgoMedio
                nivelRiesgo = 1;
            }
            else
            {
                //RiesgoBajo
                nivelRiesgo = 0;
            }

            return nivelRiesgo;
        }

        //Método que calcula la cobertura a una amenaza
        public void CalculaCoberturaControlesAmenaza()
        {
            //Rellenamos la Cobertura de Controles para CoberturaControlesAmenaza
            for (int j = 0; j < this.CoberturaControlesAmenazaActivo.Count(); j++)
            {
                this.CoberturaControlesAmenazaActivo[j].CoberturaControlesAmenaza =
                    CalculaCoberturaContrAmenaza(this.CoberturaControlesAmenazaActivo[j].ControlesAmenaza);
            }
            //Rellenamos la Cobertura de Controles para CoberturaControlesAmenazaVuln
            for (int k = 0; k < this.CoberturaControlesAmenazaVulnActivo.Count(); k++)
            {
                this.CoberturaControlesAmenazaVulnActivo[k].CoberturaControlesAmenazaVuln =
                    CalculaCoberturaContrAmenaza(this.CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln);
            }
        }

        //Método que calcula el nivel de riesgo
        public void CalculaNivelRiesgo()
        {
            int ValorActivo = this.ValorActivo;
            int contadorAmenazas = 0;
            //Inicializamos los valores
            this.NivelRiesgoAmenaza = new List<NivelRiesgo>();
            for (int i = 0; i < this.CoberturaControlesAmenazaActivo.Count(); i++)
            {
                int cont = 0;
                NivelRiesgo NuevoRiesgoAmenaza = new NivelRiesgo();
                NuevoRiesgoAmenaza.IdAmenaza = CoberturaControlesAmenazaActivo[i].IdAmenaza;
                //Los Controles NO los pongo al principio de la estructura ControlesNoParc
                for (int j = 0; j < CoberturaControlesAmenazaActivo[i].ControlesAmenaza.Count(); j++)
                {
                    ControlesCheckList NuevoControl = new ControlesCheckList();
                    if (CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].ValorControl == "NO")
                    {
                        NuevoControl.IdControl = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].IdControl;
                        NuevoControl.IdEmpresa = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].IdEmpresa;
                        NuevoControl.NivelMadurez = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].NivelMadurez;
                        NuevoControl.ValorControl = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].ValorControl;
                        NuevoRiesgoAmenaza.ControlesNoParc.Add(NuevoControl);
                        NuevoRiesgoAmenaza.CoberturaNivelAmenaza = CoberturaControlesAmenazaActivo[i].CoberturaControlesAmenaza;
                        NuevoRiesgoAmenaza.NivelRiesgoActivo = CoberturaControlesAmenazaActivo[i].CoberturaControlesAmenaza *
                                            this.ValorActivo;
                        cont++;
                    }
                }
                //Después pongo los Controles PARC al final de la estructura ControlesNoParc
                for (int j = 0; j < CoberturaControlesAmenazaActivo[i].ControlesAmenaza.Count(); j++)
                {
                    ControlesCheckList NuevoControl = new ControlesCheckList();
                    if (CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].ValorControl == "PARC")
                    {
                        NuevoControl.IdControl = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].IdControl;
                        NuevoControl.IdEmpresa = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].IdEmpresa;
                        NuevoControl.NivelMadurez = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].NivelMadurez;
                        NuevoControl.ValorControl = CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].ValorControl;
                        NuevoRiesgoAmenaza.ControlesNoParc.Add(NuevoControl);
                        NuevoRiesgoAmenaza.CoberturaNivelAmenaza = CoberturaControlesAmenazaActivo[i].CoberturaControlesAmenaza;
                        NuevoRiesgoAmenaza.NivelRiesgoActivo = CoberturaControlesAmenazaActivo[i].CoberturaControlesAmenaza *
                                                                    this.ValorActivo;
                        cont++;
                    }
                }
                //Si el contador es mayor que 0 es porque la Amenaza poseía controles NO o PARC y la añado 
                if (cont > 0)
                {
                    this.NivelRiesgoAmenaza.Add(NuevoRiesgoAmenaza);
                }
            }//Fin del for CoberturaControlesActivo

            //Inicio recorrido de CoberturaControlesAmenazaVulnActivo
            for (int k = 0; k < this.CoberturaControlesAmenazaVulnActivo.Count(); k++)
            {
                //Hago lo mismo pero para coberturaControlesAmenazaVulnActivo
                int cont = 0;
                NivelRiesgo NuevoRiesgoAmenazaVuln = new NivelRiesgo();
                NuevoRiesgoAmenazaVuln.IdAmenaza = CoberturaControlesAmenazaVulnActivo[k].IdAmenaza;
                //Los Controles NO los pongo al principio de la estructura ControlesNoParc
                for (int j = 0; j < CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln.Count(); j++)
                {
                    //bool esta = false;
                    //int IdAmenazaEsta = coberturaControlesAmenazaVulnActivo[k].IdAmenaza;
                    //esta = this.EstaAmenaza(IdAmenazaEsta);
                    //if (!esta)
                    //{
                        ControlesCheckList NuevoControl = new ControlesCheckList();
                        if (CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].ValorControl == "NO")
                        {
                            NuevoControl.IdControl = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].IdControl;
                            NuevoControl.IdEmpresa = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].IdEmpresa;
                            NuevoControl.NivelMadurez = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].NivelMadurez;
                            NuevoControl.ValorControl = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].ValorControl;
                            NuevoRiesgoAmenazaVuln.ControlesNoParc.Add(NuevoControl);
                            NuevoRiesgoAmenazaVuln.CoberturaProbabVuln = CoberturaControlesAmenazaVulnActivo[k].CoberturaControlesAmenazaVuln;
                            NuevoRiesgoAmenazaVuln.NivelRiesgoActivo = CoberturaControlesAmenazaVulnActivo[k].CoberturaControlesAmenazaVuln *
                                                                            this.ValorActivo;
                            cont++;
                        }
                    //}
                }
                //Después pongo los Controles PARC al final de la estructura ControlesNoParc
                for (int j = 0; j < CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln.Count(); j++)
                {
                    //bool esta = false;
                    //int IdAmenazaEsta = coberturaControlesAmenazaVulnActivo[k].IdAmenaza;
                    //esta = this.EstaAmenaza(IdAmenazaEsta);
                    //if (!esta)
                    //{
                        ControlesCheckList NuevoControl = new ControlesCheckList();
                        if (CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].ValorControl == "PARC")
                        {
                            NuevoControl.IdControl = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].IdControl;
                            NuevoControl.IdEmpresa = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].IdEmpresa;
                            NuevoControl.NivelMadurez = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].NivelMadurez;
                            NuevoControl.ValorControl = CoberturaControlesAmenazaVulnActivo[k].ControlesAmenazaVuln[j].ValorControl;
                            NuevoRiesgoAmenazaVuln.ControlesNoParc.Add(NuevoControl);
                            NuevoRiesgoAmenazaVuln.CoberturaProbabVuln = CoberturaControlesAmenazaVulnActivo[k].CoberturaControlesAmenazaVuln;
                            NuevoRiesgoAmenazaVuln.NivelRiesgoActivo = CoberturaControlesAmenazaVulnActivo[k].CoberturaControlesAmenazaVuln *
                                                                            this.ValorActivo;
                            cont++;
                        }
                    //}
                }
                //Si el contador es mayor que 0 es porque la Amenaza poseía controles NO o PARC y la añado 
                if (cont > 0)
                {
                    this.NivelRiesgoAmenaza.Add(NuevoRiesgoAmenazaVuln);
                }
            }
        }

        //Asocia el nivel máximo de riesgo a un activo
        public void NivelMaximoRiesgoActivo()
        {
            //Si NivelRiesgoAmenaza no contiene ningún elemento es porque no hay controles asociados
            //a las amenazas para un activo determinado o bien porque existen controles asociados
            //a las amenazas pero no hay ningun control para esa amenaza que sea del tipo NO o PARC
            //que son los que almacenamos. Por tanto, en cualquiera de los dos casos, nos encontramos
            //con un activo que no tiene amenazas o que éstas están salvaguardas por los controles
            //por lo que su nivel de Riesgo Máximo es ninguno, es decir, 0.
            if (NivelRiesgoAmenaza.Count==0)
            {
                this.MaximoRiesgoActivo = 0;
            }
            //Sino actualizamos el valor con el nivel mayor de amenaza que exista
            else
            {
                this.MaximoRiesgoActivo = this.NivelRiesgoAmenaza.First().NivelRiesgoActivo;
            }
        }

        //Método que indica si existe una amenaza
        private bool EstaAmenaza(int IdAmenazaEsta)
        {
            bool esta = false;
            for (int i = 0; i < this.NivelRiesgoAmenaza.Count(); i++)
            {
                if (this.NivelRiesgoAmenaza[i].IdAmenaza == IdAmenazaEsta)
                {
                    esta = true;
                }
            }
            return esta;
        }

        //Método que indica si la amenaza introducida por parámetros es nueva
        public bool AmenazaNueva(int NuevaAmenaza)
        {
            for (int i = 0; i < this.CoberturaControlesAmenazaActivo.Count(); i++)
            {
                if (this.CoberturaControlesAmenazaActivo[i].IdAmenaza == NuevaAmenaza)
                {
                    return false;
                }
            }
            return true;
        }

        //Método que cambia el valor de un control que no se cumplía (o se cumplía parcialmente) a un valor que indica su cumplimiento
        public void CambiaValorControl(int IdControlMaxAmenaza)
        {
            //Recorremos la Lista de NivelAmenaza CoberturaControlesAmenazaActivo del elemento RiesgoActivo
            //en el que nos encontremos (o lo que es lo mismo, en el Activo donde nos encontramos)
            for (int i = 0; i < this.CoberturaControlesAmenazaActivo.Count(); i++)
            {
                //De cada elemento de la Lista de NivelAmenaza recorremos su lista de ControlesCheckList ControlesAmenaza
                for (int j = 0; j < CoberturaControlesAmenazaActivo[i].ControlesAmenaza.Count(); j++)
                {
                    //Si el IdControl en el que estamos coincide con el IdControlMaxAmenaza cambiamos su valor a SI
                    if (CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].IdControl == IdControlMaxAmenaza)
                    {
                        CoberturaControlesAmenazaActivo[i].ControlesAmenaza[j].ValorControl = "SI";
                    }
                }
            }
            //Recorremos la Lista de ProbabilidadVulnerabilidad CoberturaControlesAmenazaVulnActivo del elemento
            //RiesgoActivo en el que nos encontremos (o lo que es lo mismo, en el Activo donde nos encontramos)
            for (int i = 0; i < this.CoberturaControlesAmenazaVulnActivo.Count(); i++)
            {
                //De cada elemento de la Lista de ProbabilidadVulnerabilidad recorremos su 
                //lista de ControlesCheckList ControlesAmenazaVulnActivo
                for (int j = 0; j < CoberturaControlesAmenazaVulnActivo[i].ControlesAmenazaVuln.Count(); j++)
                {
                    //Si el IdControl en el que estamos coincide con el IdControlMaxAmenaza cambiamos su valor a SI
                    if (CoberturaControlesAmenazaVulnActivo[i].ControlesAmenazaVuln[j].IdControl == IdControlMaxAmenaza)
                    {
                        CoberturaControlesAmenazaVulnActivo[i].ControlesAmenazaVuln[j].ValorControl = "SI";
                    }
                }
            }
        }
    }
}
